#include "lines_buffer.h"
#include <boost/shared_ptr.hpp>
	using boost::shared_ptr;
#include <boost/foreach.hpp>


//________________________________________________________________________________________

//	 operator()

//________________________________________________________________________________________
t_lines_buffer * t_lines_buffer_processor::operator()(tbb::flow_control& fc) const
{
	t_lines_buffer& buffer = *t_recyclable_buffers<t_lines_buffer, t_lines_buffer_init>::allocate();
	buffer.clear();

	// 
	// add any unprocessed line which overflowed the buffer on the last iteration
	// 
	if (shared_state->unprocessed_line.length())
	{
		buffer.add_line(shared_state->unprocessed_line.begin(), shared_state->unprocessed_line.end());
		shared_state->unprocessed_line.clear();
		assert(shared_state->cnt_lines);
		buffer.set_line_count_offset(shared_state->cnt_lines - 1);
	}
	else
	{
		buffer.set_line_count_offset(shared_state->cnt_lines);
	}
	

	assert(!buffer.is_full());

	// 
	//  ALTERNATIVE 1
	//  =============
	// 
	//  Slower but safe:
	// 
	//  	getline(istream, std::string)
	// 
	std::string line;
	line.reserve(5000);
	while (getline(input_stream, line))
	{
		++shared_state->cnt_lines;
		// break on fill
		if(!buffer.add_line(line.begin(), line.end()))
		{
			shared_state->unprocessed_line = line;
			break;
		}
	}

	// 
	//  ALTERNATIVE 2
	//  =============
	// 
	//  Hairier code which doesn't seem to be faster
	// 
	// 		istream.getline(&vector<char>.front(), 50000, '\n'))
	// 
	//	std::vector<char> line;
	//	line.reserve(50000);
	//	while (input_stream.getline(&line.front(), 50000, '\n'))
	//	{
	//		std::streamsize line_len = input_stream.gcount();
	//		if (!line_len)
	//			continue;
	//	
	//		++shared_state->cnt_lines;
	//		// break on fill
	//		if(!buffer.add_line(line.begin(), line.begin() + line_len))
	//		{
	//			shared_state->unprocessed_line.assign(line.begin(), line.begin() + line_len);
	//			break;
	//		}
	//	} 



	// 
	//  ALTERNATIVE 3
	//  =============
	// 
	//  Untested hairy code may not be faster
	// 
	//  	istream.rdbuf()->sgetn(&vector<char>.front(), BUFF_SIZE)
	// 
	//	std::vector<char> input_buffer;
	//	unsigned BUFF_SIZE = 513
	//	input_buffer.reserve(BUFF_SIZE);
	//	
	//	//  start by processing previously unprocessed line
	//	input_buffer.assign(shared_state->unprocessed_line.begin(), shared_state->unprocessed_line.end());
	//	
	//	// read up to BUFF_SIZE at a time (not including previously unprocessed)
	//	std::streambuf * pbuf = input_stream.rdbuf();
	//	std::streamsize input_buffer_len = pbuf->sgetn ( 	&input_buffer.front() + input_buffer.size(), 
	//														BUFF_SIZE - 1 - input_buffer.size() );
	//	while (input_buffer_len)
	//	{ 
	//		// 
	//		//  Enter new line at a time.
	//		//  Can write faster code but this is easier :)
	//		// 
	//		std::vector<char>::iterator beg = input_buffer.begin();
	//	 	std::vector<char>::iterator end = beg + input_buffer_len;
	//		std::vector<char>::iterator new_line_pos = std::find(beg, end, '\n');
	//		bool buffer_full = false;
	//		while (new_line_pos != end)
	//		{
	//			// Try adding line but NOT for \n to buffer
	//			if (!buffer.add_line(beg, new_line_pos - 1))
	//			{
	//				shared_state->unprocessed_line.assign(beg, end);
	//				buffer_full = true;
	//				break;
	//			}
	//			++shared_state->cnt_lines;
	//			beg = new_line_pos + 1;
	//			new_line_pos = std::find(beg, end, '\n');
	//		}
	//	
	//		// if buffer is full: stop
	//		if (buffer_full)
	//			break;
	//	
	//		// beg -> end = partial line
	//		if (beg == end)
	//			input_buffer.clear();
	//		else
	//			input_buffer.assign(beg, end);
	//		std::streamsize input_buffer_len = pbuf->sgetn ( 	&input_buffer.front() + input_buffer.size(), 
	//															BUFF_SIZE - 1 - input_buffer.size() );
	//	}

	// 
	// end of file
	// 
	if (buffer.storage.empty())
	{
		fc.stop();
		return NULL;
	}

	//std::cerr << buffer.storage.size()<< ":" << buffer.storage.capacity() << "\n";
	return &buffer;
}


